/* 
  Copyright (c) SilverLining 2015
  Date:    2016-1-7
  File:    pool_bucket.cpp  
  Description: 

*/

#include "stdafx.h"

namespace m
{
	namespace alloc
	{
		_pool_bucket::_pool_bucket(const size_t & maxSize)
			: MaxSize(maxSize)
		{
			InitializeSListHead(&_ListHead);
		}

		_pool_bucket::~_pool_bucket()
		{
			for (;;)
			{
				PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(&_ListHead);
				if (!pListEntry)
				{
					break;
				}
				_pool_node* toDelete = (_pool_node*)pListEntry;
				toDelete->~_pool_node();
				_aligned_free(toDelete);
			}
		}

		void * _pool_bucket::get(_pool* pool)
		{
			PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(&_ListHead);
			_pool_node* ret = nullptr;
			if (pListEntry)
			{
				ret = (_pool_node*)pListEntry;
				InterlockedExchangeSubtract(&pool->UnusedPoolSize, MaxSize);
			}
			else
			{
				size_t sz = sizeof(_pool_node) + MaxSize;
				void* mem = _aligned_malloc(sz, MEMORY_ALLOCATION_ALIGNMENT);
				if (mem != nullptr)
				{
					assert(sz >= sizeof(_pool_node));
					if (sz >= sizeof(_pool_node))
					{
						ret = new (mem) _pool_node();
						ret->_Pool = this;
					}
				}
			}
			if (ret)
			{
				InterlockedExchangeAdd(&pool->UsedPoolSize, MaxSize);
				return (void*)ret->Data;
			}
			return nullptr;
		}

		void _pool_bucket::put(_pool* pool, void * data)
		{
			_pool_node* node = (_pool_node*)(((uint8_t*)data) - offsetof(_pool_node, Data));
			InterlockedPushEntrySList(&node->_Pool->_ListHead, (PSLIST_ENTRY)node);
			InterlockedExchangeSubtract(&pool->UsedPoolSize, node->_Pool->MaxSize);
			InterlockedExchangeAdd(&pool->UnusedPoolSize, node->_Pool->MaxSize);
		}

		size_t _pool_bucket::clear(_pool* pool, const size_t & ClearSpace)
		{
			size_t Cleaned = 0;

			while (Cleaned <= ClearSpace)
			{
				PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(&_ListHead);
				if (!pListEntry)
				{
					break;
				}
				_pool_node* toDelete = (_pool_node*)pListEntry;
				toDelete->~_pool_node();
				_aligned_free(toDelete);
				InterlockedExchangeSubtract(&pool->UsedPoolSize, MaxSize);
				Cleaned += MaxSize;
			}

			return Cleaned;
		}

		void * _pool_bucket::operator new(size_t sz)
		{
			return ::operator new(sz, aligned);
		}

		void _pool_bucket::operator delete(void * ptr)
		{
			::operator delete(ptr, aligned);
		}
	} // alloc
} // m